﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SpotlessWeb.Helpers;
using SpotlessWeb.ViewHelpers;
using Spotless.Data;
using Spotless.Services;
using SpotlessWeb.Models;
using System.Web.Security;


namespace SpotlessWeb.Controllers
{
    public class CustomersController : Controller
    {
        public CustomersController () : this(null, null)
        {
        }

        public CustomersController(Spotless.Services.CustomerService customerService, Spotless.Services.QueryService queryService)
        {
            this.CustomerService = customerService ?? new Spotless.Services.CustomerService();
            this.QueryService = queryService ?? new Spotless.Services.QueryService();
        }

        protected Spotless.Services.CustomerService CustomerService { get; private set; }
        protected Spotless.Services.QueryService QueryService { get; private set; }

        //
        // GET: /Customers/

        [Authorize(Roles = "Admin")]

        public ActionResult Index(string sort, int? page)
        {
            var filters = GetCustomersFilters();
            ViewData.SetFilters(filters);
            var data = CustomerService.GetAllCustomers(filters.ToDictionary(x => x.Value, x => Request["filter." + x.Key.DisplayName.Replace(" ", "")]), sort, page ?? 0, 20);
            return View(data);
        }

        public ActionResult DownloadCustomers()
        {
            var filters = GetCustomersFilters();
            
            var data = CustomerService.GetAllCustomers(filters.ToDictionary(x => x.Value, x => Request["filter." + x.Key.DisplayName.Replace(" ", "")]));//                .OrderBy(x => x.FirstName).ToArray();
            
            var csv = new ActionResults.CSVActionResult();
            csv.Name = string.Format("Customers.csv");
            csv.ContentHeaders = GetCSVHeaders();
            csv.Rows = data.Select(x => GetCustomerCSVData(x)).ToList();
            return csv;
        }

        private new Dictionary<FilterExpressionInfo, FilterExpression<Customer>> GetCustomersFilters()
        {
            var firstNameFilterInfo = FilterExpressionInfo.TextBox("First Name");
            var lastNameFilterInfo = FilterExpressionInfo.TextBox("Last Name");
            var addressLine1FilterInfo = FilterExpressionInfo.TextBox("AddressLine 1");
            var addressLine2FilterInfo = FilterExpressionInfo.TextBox("AddressLine2");
            var townFilterInfo = FilterExpressionInfo.TextBox("Town");
            var countyFilterInfo  = FilterExpressionInfo.TextBox("County");
            var postCodeFilterInfo  = FilterExpressionInfo.TextBox("PostCode");
            var countryFilterInfo  = FilterExpressionInfo.TextBox("Country");
            var emailFilterInfo  = FilterExpressionInfo.TextBox("Email");
            var phoneMobileFilterInfo = FilterExpressionInfo.TextBox("PhoneMobile");
            var phoneLandlineFilterInfo = FilterExpressionInfo.TextBox("PhoneLandline");
            var dateOfBirthFilterInfo = FilterExpressionInfo.TextBox("DateOfBirth", new { @class = "dateInput" });

            var methodFilterInfo = FilterExpressionInfo.DropDown("Method", SelectListHelpers.GetSelectListFromEnumUsingValues<Spotless.Data.Customer.Methods>());

            var lastContactDateFilterInfo = FilterExpressionInfo.TextBox("LastContactDate");
            var productCategoryFilterInfo = FilterExpressionInfo.DropDown("Product Category", QueryService.GetCategories().Select(x => new SelectListItem() { Text = x.Name, Value = x.CategoryId.ToString() }));
            var productNameFilterInfo = FilterExpressionInfo.TextBox("Product Name");
            
            return new Dictionary<FilterExpressionInfo, FilterExpression<Customer>>{
                {firstNameFilterInfo, new FilterExpression<Customer>(x => x.FirstName, FilterTypes.Contains)},
                {lastNameFilterInfo, new FilterExpression<Customer>(x => x.LastName, FilterTypes.Contains)},
                {addressLine1FilterInfo, new FilterExpression<Customer>(x => x.AddressLine1, FilterTypes.Contains)},
                {addressLine2FilterInfo, new FilterExpression<Customer>(x => x.AddressLine2, FilterTypes.Contains)},
                {townFilterInfo, new FilterExpression<Customer>(x => x.Town, FilterTypes.Contains)},
                {countyFilterInfo, new FilterExpression<Customer>(x => x.County, FilterTypes.Contains)},
                {postCodeFilterInfo, new FilterExpression<Customer>(x => x.PostCode, FilterTypes.Contains)},
                
                {methodFilterInfo, new FilterExpression<Customer>(x => x.MethodId, FilterTypes.EqualTo)},
                

                {countryFilterInfo, new FilterExpression<Customer>(x => x.Country, FilterTypes.Contains)},
                {emailFilterInfo, new FilterExpression<Customer>(x => x.Email, FilterTypes.Contains)},
                {phoneMobileFilterInfo, new FilterExpression<Customer>(x => x.PhoneMobile, FilterTypes.Contains)},
                {phoneLandlineFilterInfo, new FilterExpression<Customer>(x => x.PhoneLandline, FilterTypes.Contains)},
                
                {dateOfBirthFilterInfo, new FilterExpression<Customer>(x => x.DateOfBirth, FilterTypes.Contains)},
                {lastContactDateFilterInfo, new FilterExpression<Customer>(x => x.LastContactDate, FilterTypes.GreaterThanOrEqual)},
                
                {productCategoryFilterInfo, new FilterExpression<Customer>(x => x.CategoryId, FilterTypes.EqualTo)},
                {productNameFilterInfo, new FilterExpression<Customer>(x => x.Product.Name, FilterTypes.Contains)},
                
                //{priorityFilterInfo, new FilterExpression<Query>(x => x.Priority, FilterTypes.EqualTo)},
                //{dateFromFilterInfo, new FilterExpression<Query>(x => x.EnquiryDate, FilterTypes.GreaterThanOrEqual)},
                //{dateToFilterInfo, new FilterExpression<Query>(x => x.EnquiryDate, FilterTypes.LessThanOrEqual)}
            };
        }

        private string[] GetCSVHeaders()
        {
            return new string[]{
                "First Namee",
                "Last Name",
                "Method",
                "Product Category",
                "Product Name",
                //"Priority"
            };
        }

        public string[] GetCustomerCSVData(Customer customer)
        {
            return new string[]{
                customer.FirstName.ToString(),
                customer.LastName.ToString(),
                customer.Method.ToString(),
                customer.Category != null ? customer.Category.Name : "",
                customer.Product != null ? customer.Product.Name : "",
                
                //customer.EnquiryDate.ToShortDateString(),
                //query.LastName + (query.FirstName.HasValue() ? ", " + query.FirstName : ""),
                //query.QueryType.ToDisplayString(),
                //customer.Category != null ? customer.Category.Name : "",
                //customer.Product != null ? customer.Product.Name : "",
                //query.Priority.ToString()
            };
        }

        

        //
        // GET: /Customers/Detail/5

        public ActionResult Details(int id)
        {
            var customer = CustomerService.GetCustomerGetById(id);


            return View(customer);
        }


        
        //
        // GET: /Customers/Create

        [Authorize(Roles = "Admin")]
        public ActionResult Create()
        {
            ViewData.AddCategories(CustomerService.GetCategories());
            return View();  
        } 

        //
        // POST: /Customers/Create
        
        [HttpPost]
        public ActionResult Create(FormCollection collection)
        {
            var customer = CustomerService.CreateCustomer();
            SetValuesFromDrillDowns(customer, collection);

            TryUpdateModel(customer, new string[]{
                "FirstName",
                "LastName",
                "AddressLine1",
                "AddressLine2",
                "Town",
                "County",
                "PostCode",
                "Country",
                "LastContactDate",
                "Method",
                "Email",
                "PhoneMobile",
                "PhoneLandline",
                "DateOfBirth",
                "CategoryId",
                "ProductId",
                "SampleRequest"});

            if (ModelState.IsValid)
            {
                CustomerService.SaveChanges();
                
                return RedirectToAction("Index");
            }

            ViewData.AddCategories(QueryService.GetCategories());
            return View(customer);

        }

        //
        // GET: /Customers/Edit/5
        [Authorize(Roles = "Admin")]
        public ActionResult Edit(int id)
        {
            var data = CustomerService.GetCustomerGetById(id);
            return View(data);
            //ViewData.AddCategories(CustomerService.GetCategories());
            //return View();  
        }

        
        [HttpPost]
        public ActionResult Edit(int id, FormCollection collection)
        {
            var customer = CustomerService.GetCustomerGetById(id);

            TryUpdateModel(customer);

            if (ModelState.IsValid)
            {
                CustomerService.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(customer);
        }

        //
        // GET: /Customers/Delete/5
        [Authorize(Roles = "Admin")]
        public ActionResult Delete(int id)
        {
            return View();
        }

        //
        // POST: /Customers/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, FormCollection collection)
        {
            try
            {
                // TODO: Add delete logic here
 
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        public ActionResult DrillDown(int? id, FormCollection collection)
        {
            var data = new Models.CustomerDrillDownViewModel();
            data.AllowEdit = true;
            if (id.HasValue && id.Value > 0)
            {
                data.Customer = CustomerService.GetById(id.Value);
            }
            if (data.Customer == null)
            {
                data.Customer = new Customer();
            }
            data.DrillDowns = new DrillDown[0];
            
            if (collection.AllKeys.Count() > 0)
                SetValuesFromDrillDowns(data.Customer, collection);

            if (data.Customer.CategoryId.HasValue && data.Customer.CategoryId > 0 && (data.Customer.Category == null || data.Customer.CategoryId != data.Customer.Category.CategoryId))
            {
                data.Customer.Category = QueryService.GetCategoryById(data.Customer.CategoryId.Value);
            }

            if (data.Customer.Category == null)
            {
                data.Categories = QueryService.GetCategories().ToArray();
            }
            else
            {
                data.Customer.Product = EnsureDrillDownLoaded(data.Customer.ProductId, data.Customer.Product);

                if (data.Customer.Product == null)
                {
                    data.DrillDowns = QueryService.GetTopLevelDrillDown(data.Customer.CategoryId.Value, Spotless.Data.DrillDown.DrillDownTypes.Product).ToArray();
                }
                else
                {
                    data.DrillDowns = CustomerService.GetDrillDownsByParentId(data.Customer.ProductId.Value, Spotless.Data.DrillDown.DrillDownTypes.Product).ToArray();
                }
            }


            return PartialView("Partial/DrillDown", data);
        }

        private int? GetIntValue(string key, FormCollection collection)
        {
            int val = 0;
            if (int.TryParse(collection[key], out val))
                return val;
            else
                return null;
        }

        private void SetValuesFromDrillDowns(Customer customer, FormCollection collection)
        {
            //set drill down values manually
            if (collection["Customer.CategoryId"] != null)
            {
                customer.CategoryId = GetIntValue("Customer.CategoryId", collection) ?? 0;
                if (customer.CategoryId == 0)
                    ModelState.AddModelError("Customer.CategoryId", "Category must be selected");
            }

            if (ModelState.IsValid && collection["Customer.ProductId"] != null)
            {
                customer.ProductId = GetIntValue("Customer.ProductId", collection);
                customer.Product = EnsureDrillDownLoaded(customer.ProductId, customer.Product);
                if (customer.Product == null || customer.Product.Children.Count(x => x.Type == Spotless.Data.DrillDown.DrillDownTypes.Product) > 0)
                {
                    ModelState.AddModelError("Customer.ProductId", "Product must be selected");
                }
            }
            else
            {
                customer.ProductId = null;
                customer.Product = null;
            }

        }

        private DrillDown EnsureDrillDownLoaded(int? id, DrillDown item)
        {
            if (id > 0 && (item == null || id != item.DrillDownId))
            {
                return CustomerService.GetDrillDownById(id.Value);
            }
            else
            {
                return item;
            }
        }
    }
}
